# -*- coding: utf-8 -*-
"""
aimfc.py - 目标函数demo
描述:
    Geatpy的目标函数遵循本案例的定义方法，传入种群表现型矩阵Phen，以及可行性列向量LegV
    若没有约束条件，也需要返回LegV
    若要改变目标函数的输入参数、输出参数的格式，则需要修改或自定义算法模板
"""

import numpy as np

def aimfuc(Phen, LegV):
    x1 = Phen[:, [0]]
    x2 = Phen[:, [1]]
    x3 = 1 - x1 - x2 # 将x1 + x2 + x3 = 1的等式约束降维化处理
    f = 4 * x1 + 2 * x2 + x3
    # 约束条件
    idx1 = np.where(2 * x1 + x2 > 1)[0]
    idx2 = np.where(x1 + 2 * x3 > 2)[0]
    idx3 = np.where(x1 + x2 > 1)[0]
    exIdx = np.unique(np.hstack([idx1, idx2, idx3])) # 得到非可行解在种群中的下标
    
    # 惩罚方法1：修改非可行个体的目标函数值的方法，对非可行解对应的目标函数值作出惩罚，而不标记其为非可行解
    # 不标记非可行解的做法比较危险，假如处理不慎，可能会导致以下错误情况：
    # 某一代的种群全是非可行解而其最优的目标函数值恰好是历代最优的情况出现。
    # 此时进化记录器会受到欺骗，而得出一个实际上是非可行解的搜索结果。
    # 一个比较好的处理方法是：要让其绝对地比其他任何可行解的目标函数值都要大或小（看是最小化目标还是最大化目标）。
#    f[exIdx] = -1
    
    # 惩罚方法2： 标记非可行解在可行性列向量中对应的值为0，并编写punishing罚函数来修改非可行解的适应度。
    # 也可以不写punishing，因为Geatpy内置的算法模板及内核已经对LegV标记为0的个体的适应度作出了修改。
    # 使用punishing罚函数实质上是对非可行解个体的适应度作进一步的修改
    LegV[exIdx] = 0 # 对非可行解作出标记，使其在可行性列向量中对应的值为0
    
    return [f,LegV]
